//
// Created by admin on 2024/8/19.
//

#ifndef RATES_FLAT_TIMER_WHEEL_H
#define RATES_FLAT_TIMER_WHEEL_H

#include <atomic>
#include <iostream>
#include <thread>
#include <utility>
#include <vector>
#include <mutex>
#include <unordered_map>
#include "timer-wheel.h"

namespace timewheel {

struct ScheduleInfo {
    Tick wholeDuration_;
    int num_;
    int idx_;

    ScheduleInfo(Tick wholeDuration, int num, int idx)
            : wholeDuration_(wholeDuration), num_(num), idx_(idx) {}
};

class BaseTask {
public:
    explicit BaseTask(std::string taskId)
            : inc_timer_(this), taskId_(std::move(taskId)) {}
    virtual ~BaseTask() {}

    std::string& getTaskId() {
        return taskId_;
    }

    bool buildSchedule(TimerWheel* timers, Tick wholeDuration, int num, int idx) {
        changeSchedule(wholeDuration, num, idx);
        if (!enable_) {
            enable_ = true;
            start(timers);
            duration_next_ = duration();
        }
        return true;
    }

    void start(TimerWheel* timers) {
        if (enable_) {
            timers->schedule(&inc_timer_, duration_next_);
        }
    }

    bool stop(TimerWheel* timers) {
        enable_ = false;
        inc_timer_.cancel();
        return true;
    }

    bool restart(TimerWheel* timers) {
        enable_ = true;
        start(timers);
        return true;
    }

    std::string getInfo() {
        return "scheduleAt:" + std::to_string(inc_timer_.scheduled_at()) +
               " duration:" + std::to_string(schedule_info_next_.wholeDuration_) +
               " subDuration:" + std::to_string(schedule_info_next_.wholeDuration_ / schedule_info_next_.num_) +
               " num:" + std::to_string(schedule_info_next_.num_) +
               " idx:" + std::to_string(schedule_info_next_.idx_);
    }

    virtual void execute() = 0;

private:
    bool changeSchedule(Tick nextWholeDuration, int nextNum, int nextIdx) {
        schedule_info_next_ = {nextWholeDuration, nextNum, nextIdx};
        duration_next_ = duration();
        schedule_info_ = {nextWholeDuration, nextNum, nextIdx};
        return true;
    }

    void call(TimerWheel* timer) {
        if (!enable_) {
            return;
        }
        start(timer);
        if (!isRunning_) {
            isRunning_ = true;
            execute();
            isRunning_ = false;
        }
    }

    /**
     * 计算下一个任务时间
     */
    Tick duration() const {
        Tick nextWholeDuration = schedule_info_next_.wholeDuration_;
        int nextNum = schedule_info_next_.num_;
        Tick nextIdx = schedule_info_next_.idx_;

        if (schedule_info_.wholeDuration_ == 0) {
            return (nextWholeDuration / nextNum) * nextIdx;
        }

        Tick wholeDuration = schedule_info_.wholeDuration_;
        int num = schedule_info_.num_;
        Tick idx = schedule_info_.idx_;

        return (nextWholeDuration / nextNum * nextNum) + (((nextWholeDuration / nextNum) * nextIdx) - ((wholeDuration / num) * idx));
    }

private:
    /**
     * 定时器回调
     */
    MemberTimerEvent<BaseTask, &BaseTask::call> inc_timer_;
    /**
     * 任务调度信息
     */
    ScheduleInfo schedule_info_{0, 0, 0};
    ScheduleInfo schedule_info_next_{0, 0, 0};
    /**
     * 任务调度信号量
     * -
     */
    std::string taskId_;
    std::atomic<Tick> duration_next_{0};
    std::atomic<bool> enable_ = {false};
    std::atomic<bool> isRunning_ = {false};
};

class TaskManager {

public:
    TaskManager() {
        // 创建一个单独线程处理定时器
        std::thread([this]() {
            while (true) {
                if (enable_) {
                    // todo 根据是否有任务决定是否运转时间轮
                    timers_.advance(10);
                    std::this_thread::sleep_for(std::chrono::milliseconds(10));
                } else {
                    std::this_thread::sleep_for(std::chrono::milliseconds(1000));
                }
            }
        }).detach();
    }

    ~TaskManager() {
        // 设置停止标志
        enable_ = false;
    }

    bool start() {
        if (!enable_) {
            enable_ = true;
            return true;
        }
        return false;
    }

    bool registScene(const std::string& sceneCode, const Tick wholeDuration) {
        std::vector<std::shared_ptr<BaseTask>> sceneTasks;
        sceneTasks_[sceneCode] = sceneTasks;
        task_durations_[sceneCode] = wholeDuration;
        return true;
    }

    bool unregistScene(const std::string& sceneCode) {
        task_durations_.erase(sceneCode);
        auto it = sceneTasks_.find(sceneCode);
        for (auto& task : it->second) {
            task->stop(&timers_);
        }
        sceneTasks_.erase(sceneCode);
        task_durations_.erase(sceneCode);
        return true;
    }


    bool batchPutTask(const std::string& sceneCode, const std::vector<std::shared_ptr<BaseTask>>& tasks) {
        std::lock_guard<std::recursive_mutex> lock(mtx_);
        auto it = sceneTasks_.find(sceneCode);
        if (it == sceneTasks_.end()) {
            // 返回 false 表示场景未找到，而不是抛出异常
            return false;
        }

        for (const auto& task : tasks) {
            sceneTasks_[sceneCode].emplace_back(task);
        }
        reIndex(sceneCode);
        return true;

    }

    bool batchRemoveTask(const std::string& sceneCode, const std::vector<std::string>& taskIds) {
        std::lock_guard<std::recursive_mutex> lock(mtx_);
        auto it = sceneTasks_.find(sceneCode);
        if (it == sceneTasks_.end()) {
            // 返回 false 表示场景未找到，而不是抛出异常
            return false;
        }
        auto &tasks = it->second;
        std::vector<size_t> toDelete;

        // 标记需要删除的任务
        for (size_t i = 0; i < tasks.size(); ++i) {
            for (const auto &taskId: taskIds) {
                if (tasks[i]->getTaskId() == taskId) {
                    toDelete.push_back(i);
                    break;
                }
            }
        }

        // 按照逆序删除元素，避免下标偏移
        for (auto item = toDelete.rbegin(); item != toDelete.rend(); ++item) {
            size_t idx = *item;
            tasks[idx]->stop(&timers_);
            tasks.erase(tasks.begin() + idx);
        }
        sceneTasks_[sceneCode] = tasks;
        reIndex(sceneCode);
        return true;
    }

    bool putTask(const std::string& sceneCode, const std::shared_ptr<BaseTask>& task) {
        std::lock_guard<std::recursive_mutex> lock(mtx_);
        return batchPutTask(sceneCode, {task});
    }

    bool removeTask(const std::string& sceneCode, const std::string& taskId) {
        std::lock_guard<std::recursive_mutex> lock(mtx_);
        return batchRemoveTask(sceneCode, {taskId});
    }


private:
    void reIndex(const std::string& sceneCode) {
        std::lock_guard<std::recursive_mutex> lock(mtx_);
        auto it = sceneTasks_.find(sceneCode);
        Tick duration = task_durations_[sceneCode];
        int num = it->second.size();
        for (int j = 0; j < it->second.size(); ++j) {
            auto task = it->second.at(j);
            task->buildSchedule(&timers_, duration,  num, j + 1);
        }
    }

    std::unordered_map<std::string, std::vector<std::shared_ptr<BaseTask>>> sceneTasks_;
    std::unordered_map<std::string, Tick> task_durations_;
    TimerWheel timers_;
    std::recursive_mutex mtx_;
    std::atomic<bool> enable_ = {true};
};

}
#endif //RATES_FLAT_TIMER_WHEEL_H
